package com.moli.iov.down.command.mq;

import com.alibaba.fastjson.JSONObject;
import com.moli.iov.cache.RedisUtil;
import com.moli.iov.down.constants.Constant;
import com.moli.iov.down.enums.command.CommandEnum;
import com.moli.iov.down.enums.ResResultEnum;
import com.moli.iov.down.enums.command.ResposeCommandEnum;
import com.moli.iov.down.enums.command.upgrade.UpgradeStatusEnum;
import com.moli.iov.down.model.dto.remoting.BluetoothPwdDto;
import com.moli.iov.down.model.dto.remoting.CommandDto;
import com.moli.iov.down.command.codec.decode.bean.QueryResBean;
import com.moli.iov.down.command.codec.decode.bean.UpgradeResBean;
import com.moli.iov.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * <p>
 *  下发命令缓存
 * </p>
 *
 * @author: zql
 * @Date: 2018/11/28 17:47
 */
@Component("sendCache")
public class SendCache {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private RedisUtil redisUtil;

    /**
     * 下发命令缓存 命令结果与控制命令
     * @param commandDto
     */
    public void addResultAndControlCommand(CommandDto commandDto){
        long time = Constant.VIN_COMMAND_RESPONSE_TIME;
        if(CommandEnum.REMOTE_UPGRADE.getFlag() == commandDto.getCommand()){
            time = Constant.UPGRADE_CACHE_TIME;
        }
        addRedis(commandDto, time);
    }

    /**
     * 下发命令添加缓存标识，用于判断是否终端响应
     * @param commandDto
     * @param time
     */
    public void addRedis(CommandDto commandDto, long time){
        commandDto.setResult(ResResultEnum.SEND.getFlag());
        String key = getResKey(commandDto);
        redisUtil.set(key, JSONObject.toJSONString(commandDto), time);

        logger.info("[命令下发] 添加缓存  key:{} 时间：{} 数据：{} ",
                key, commandDto, Constant.VIN_COMMAND_RESPONSE_TIME);
    }

    /**
     * 返回redis缓存结果
     * @param vin
     * @param command
     * @param serialNumber
     * @return
     */
    public CommandDto getCacheSendCommand(String vin,byte command, String serialNumber){
        CommandDto commandDto = new CommandDto();
        commandDto.setVin(vin);
        commandDto.setCommand(command);
        commandDto.setCommandNo(Long.parseLong(serialNumber));
        return this.getCacheSendCommand(commandDto);
    }

    /**
     * 返回redis缓存结果
     * @param commandDto
     * @return
     */
    public CommandDto getCacheSendCommand(CommandDto commandDto){
        String resultStr = redisUtil.get(getResKey(commandDto));
        if(StringUtil.isNotBlank(resultStr)){
            return JSONObject.parseObject(resultStr, CommandDto.class);
        }
        return null;
    }

    /**
     * 更新终端响应状态
     * @param commandDto
     */
    public void updateResResult(CommandDto commandDto, CommandDto commandDtoCache){
        long time = Constant.VIN_COMMAND_RESPONSE_TIME;
        if(CommandEnum.REMOTE_UPGRADE.getFlag() == commandDto.getCommand()){
            time = Constant.UPGRADE_CACHE_TIME;
        }
        redisUtil.set(getResKey(commandDto), JSONObject.toJSONString(commandDtoCache), time);
    }

    /**
     * 返回redis缓存key
     * @param commandDto
     * @return
     */
    private String getResKey(CommandDto commandDto){
        String command = StringUtil.bytesToHexString(commandDto.getCommand());
        if(CommandEnum.REMOTE_UPGRADE.getFlag() == commandDto.getCommand()){
            return Constant.VIN_COMMAND_RESPONSE + commandDto.getVin() + ":" + command;
        }

        return Constant.VIN_COMMAND_RESPONSE + commandDto.getVin() + ":" + command + ":" + commandDto.getCommandNo();
    }

    /**
     * 参数查询响应 缓存 redis
     * @param decode
     */
    public void setParameterQueryCache(QueryResBean decode){
        logger.info("参数查询响应 存入redis vin:{}, 数据：{}", decode.getVin(), decode);
        //参数查询响应
        redisUtil.set(Constant.VIN_PARAMETER_QUERY_RES + decode.getVin(), JSONObject.toJSONString(decode), Constant.VIN_PARAMETER_QUERY_RES_TIME);
    }

    /**
     * 查询 参数响应 缓存
     * @param vin
     * @return
     */
    public QueryResBean  queryParamterCache(String vin){
        String result = redisUtil.get(Constant.VIN_PARAMETER_QUERY_RES + vin);
        if(StringUtil.isBlank(result)){
            return null;
        }
        return JSONObject.parseObject(result, QueryResBean.class);
    }


    /**
     * 更新缓存状态, 终端已响应 普通命令
     * @param vin
     * @param serialNumber
     */
    public void updateResResult(String vin, byte command, String serialNumber){
        Byte sendCommand = ResposeCommandEnum.getCommandEnum(command);

        String commandStr = StringUtil.bytesToHexString(command);

        if(sendCommand == null){

            logger.error("[上行响应报文] 终端已响应 更新缓存状 失败 转换发送命令为Null vin:{}, command:{}, serialNumber:{}",
                    vin, commandStr, serialNumber);
            return;
        }

        CommandDto commandDtoResult = this.getCacheSendCommand(vin, sendCommand, serialNumber);
        String sendCommandStr = StringUtil.bytesToHexString(sendCommand);
        if(commandDtoResult == null){

            logger.error("[上行响应报文] 终端已响应 更新缓存状 失败 缓存结果为空  vin:{}, command:{}, serialNumber:{}",
                    vin, sendCommandStr, serialNumber);
            return;
        }

        String resultCommandStr = StringUtil.bytesToHexString(commandDtoResult.getCommand());

        logger.info("[上行响应报文] 终端已响应 更新缓存状态 vin: {}, command: {}, " +
                        "serialNumber: {}, result:{}, sendingTimes:{}, commandDtoResult:{}",
                vin, resultCommandStr, commandDtoResult.getCommandNo(), commandDtoResult.getResult(),
                commandDtoResult.getSendingTimes(), commandDtoResult);

        commandDtoResult.setResult(ResResultEnum.SUCCESS.getFlag());
        this.updateResResult(commandDtoResult, commandDtoResult);
    }

    /**
     * 更新 升级响应状态
     * @param decode
     */
    public void updateUpgrdateResResult(UpgradeResBean decode){

        CommandDto commandDtoResult = this.getCacheSendCommand(
                decode.getVin(), CommandEnum.REMOTE_UPGRADE.getFlag(), String.valueOf(decode.getSerialNumber()));

        if(commandDtoResult == null){
            logger.error("[上行响应报文] 更新升级响应状态 失败 缓存结果为空  vin:{}, serialNumber:{}",
                    decode.getVin(), decode.getSerialNumber());
            return;
        }

        commandDtoResult.setUpgradeStatus(decode.getUpgradeStatus());
        if(UpgradeStatusEnum.UPADATE_SUCCESSED.getFlag() == decode.getUpgradeStatus()){
            commandDtoResult.setResult(ResResultEnum.SUCCESS.getFlag());
        }

        this.updateResResult(commandDtoResult, commandDtoResult);
    }

    /**
     * 获取升级命令 下发的流水号
     * @param decode
     * @return
     */
    public String getUpgradeSerialNumber(UpgradeResBean decode){
        CommandDto commandReqDto = new CommandDto();
        commandReqDto.setVin(decode.getVin());
        commandReqDto.setCommand(CommandEnum.REMOTE_UPGRADE.getFlag());

        CommandDto cacheSendCommand = getCacheSendCommand(commandReqDto);
        if(cacheSendCommand == null ||cacheSendCommand.getCommandNo() == null){
            return "";
        }

        return String.valueOf(cacheSendCommand.getCommandNo());
    }


    /**
     * 获取发送序号
     * @param vin
     * @return
     */
    public long getSerialNumber(String vin){
        return redisUtil.incr(Constant.VIN_COMMAND_INCR + vin);
    }

    /**
     * 设置蓝牙新密码缓存
     * @param bluetoothPwdDto
     */
    public void setBluetoothNewPwd(String vin, BluetoothPwdDto bluetoothPwdDto){
        redisUtil.set(Constant.BLUETOOTH_NEW_PWD + vin, JSONObject.toJSONString(bluetoothPwdDto));
    }

    /**
     * 获取蓝牙最新密码
     * @return
     */
    public BluetoothPwdDto getBluetoothNewPwd(String vin){
        String s = redisUtil.get(Constant.BLUETOOTH_NEW_PWD + vin);
        if(StringUtil.isBlank(s)){
            return null;
        }

        return JSONObject.parseObject(s, BluetoothPwdDto.class);
    }

}
